#include "lyricspage.h"

#include "music.h"
#include "ui_lyricspage.h"

LyricsPage::LyricsPage(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::LyricsPage)
{
    ui->setupUi(this);

    // 设置窗口无边框标志
    setWindowFlag(Qt::FramelessWindowHint);
    // 设置窗口背景透明属性（当前被注释掉）
    // setAttribute(Qt::WA_TranslucentBackground);
    // 设置窗口大小为1017x671像素
    resize(1017, 671);

    // 创建一个属性动画对象，用于控制窗口的几何形状变化
    animal_ = new QPropertyAnimation(this, "geometry", this);
    // 设置动画持续时间为500毫秒
    animal_->setDuration(500);
    // 设置动画的起始值为当前位置
    animal_->setStartValue(QRect(10, 10, width(), height()));
    // 设置动画的结束值为向下移动一个窗口高度的位置
    animal_->setEndValue(QRect(10, 10 + height(), width(), height()));

    // 连接隐藏按钮的点击信号到动画的启动槽函数
    connect(ui->hideBtn, &QPushButton::clicked, this, [=]() {
        animal_->start();
    });

    // 连接动画的完成信号到窗口的隐藏槽函数
    connect(animal_, &QPropertyAnimation::finished, this, [=]() {
        hide();
    });

    // 为隐藏按钮设置图标
    ui->hideBtn->setIcon(QIcon(":/images/xiala.png"));
}
/**
 * @brief 解析歌词文件
 * @param lrc_path 歌词文件的路径
 * @return bool 解析成功返回true，失败返回false
 * @details 该函数负责读取并解析指定路径的歌词文件（.lrc格式）。
 *          解析过程包括：
 *          1. 打开歌词文件
 *          2. 逐行读取歌词内容
 *          3. 解析每行歌词的时间标签和文本内容
 *          4. 将解析结果存储到lrc_lines_成员变量中
 *          5. 时间标签格式为[mm:ss.ff]，其中mm为分钟，ss为秒，ff为百分之一秒
 * @note 歌词行会按照时间顺序存储在lrc_lines_中
 */
bool LyricsPage::parseLrc(const QString &lrc_path)
{
    // 清空已存储的歌词行
    lrc_lines_.clear();
    // 打开歌词文件
    QFile lrc_file(lrc_path);
    // 如果文件打开失败，输出调试信息并返回false
    if (!lrc_file.open(QFile::ReadOnly))
    {
        Debug << "打开文件:" << lrc_path;
        return false;
    }

    // 逐行读取歌词文件
    while (!lrc_file.atEnd())
    {
        // 读取一行歌词
        QString lrc_word = lrc_file.readLine(1024);

        // 查找时间标签的起始和结束位置
        int left = lrc_word.indexOf('[');
        int right = lrc_word.indexOf(']');

        // 初始化时间变量
        qint64 line_time = 0;
        int start = 0;
        int end = 0;
        // 提取时间标签字符串
        QString time = lrc_word.mid(left, right - left + 1);

        // 解析分钟部分
        start = 1;
        end = time.indexOf(':');
        line_time += lrc_word.mid(start, end - start).toInt() * 60 * 1000;

        // 解析秒部分
        start = end + 1;
        end = time.indexOf('.', start);
        line_time += lrc_word.mid(start, end - start).toInt() * 1000;

        // 解析毫秒部分
        start = end + 1;
        end = time.indexOf('.', start);
        line_time += lrc_word.mid(start, end - start).toInt();

        // 提取歌词文本
        QString word = lrc_word.mid(right + 1).trimmed();

        // 将解析出的时间和文本存入歌词行列表
        lrc_lines_.push_back(LyricLine(line_time, word.trimmed()));
    }
    // 输出所有歌词行的时间戳和文本（调试用）
    for (auto &word : lrc_lines_)
        Debug << word.time << word.text;
    // 解析成功，返回true
    return true;
}
/**
 * @brief 根据播放时间获取对应的歌词行索引
 * @param pos 当前播放时间（毫秒）
 * @return 返回与播放时间对应的歌词行索引，如果没有找到则返回-1或边界索引
 * @details 该函数通过比较当前播放时间与歌词行的时间戳，确定当前应该显示的歌词行。
 *          算法逻辑如下：
 *          1. 如果歌词行列表为空，返回-1
 *          2. 如果第一行歌词时间大于当前播放时间，返回0
 *          3. 遍历歌词行列表，找到当前播放时间所在的区间，返回对应索引
 *          4. 如果播放时间超过所有歌词时间，返回最后一行的索引
 * @note 歌词行必须按照时间顺序排列，此函数才能正确工作
 */
int LyricsPage::getLineLrcWordIndex(const qint64 pos)
{
    // 检查歌词行列表是否为空，若为空则返回-1
    if (lrc_lines_.isEmpty())
        return -1;
    // 检查当前播放位置是否在第一行歌词之前，若是则返回0
    if (lrc_lines_[0].time > pos)
        return 0;
    // 遍历歌词行列表，查找当前播放位置所在的歌词行索引
    for (int i = 1; i < lrc_lines_.size(); ++i)
    {
        // 如果当前位置在上一行歌词时间和当前行歌词时间之间，则返回上一行的索引
        if (pos > lrc_lines_[i - 1].time && pos <= lrc_lines_[i].time)
            return i - 1;
    }
    // 如果遍历结束仍未找到匹配项，则返回最后一行歌词的索引
    return lrc_lines_.size() - 1;
}
/**
 * @brief 根据索引获取歌词行文本
 * @param index 歌词行索引
 * @return 返回指定索引位置的歌词文本，如果索引无效则返回空字符串
 * @details 该函数根据提供的索引从歌词行列表中获取对应的歌词文本。
 *          如果索引小于0或大于等于歌词行列表的大小，则返回空字符串。
 * @note 此函数用于获取特定行号的歌词内容，常用于显示歌词
 */
QString LyricsPage::getLineWord(const qint64 index)
{
    // 检查索引是否超出范围
    if (index < 0 || index >= lrc_lines_.size())
        return ""; // 如果索引无效，返回空字符串
    // 返回指定索引位置的歌词文本
    return lrc_lines_[index].text;
}
/**
 * @brief 显示指定时间点的歌词内容
 * @param time 当前播放时间（毫秒）
 * @details 根据当前播放时间显示对应的歌词内容，包括当前行及其前后的歌词行。
 *          显示布局为：
 *          - 当前播放时间点前三行歌词
 *          - 当前播放时间点对应的歌词（居中显示）
 *          - 当前播放时间点后三行歌词
 *          如果没有找到对应时间点的歌词，则显示"当前歌曲无歌词"提示
 */
void LyricsPage::showLrcWord(const int time)
{
    // 根据当前时间获取对应的歌词行索引
    const int index = getLineLrcWordIndex(time);
    // 如果索引为-1，表示没有找到对应的歌词
    if (index == -1)
    {
        // 清空所有歌词行，并显示"当前歌曲无歌词"提示
        ui->line1->setText("");
        ui->line2->setText("");
        ui->line3->setText("");
        ui->lineCenter->setText("当前歌曲无歌词");
        ui->line4->setText("");
        ui->line5->setText("");
        ui->line6->setText("");
    }
    else
    {
        // 显示当前时间点前后的歌词内容
        // 显示当前行前三句歌词
        ui->line1->setText(getLineWord(index - 3));
        ui->line2->setText(getLineWord(index - 2));
        ui->line3->setText(getLineWord(index - 1));
        // 显示当前行歌词
        ui->lineCenter->setText(getLineWord(index));
        // 显示当前行后三句歌词
        ui->line4->setText(getLineWord(index + 1));
        ui->line5->setText(getLineWord(index + 2));
        ui->line6->setText(getLineWord(index + 3));
    }
}

LyricsPage::~LyricsPage()
{
    delete ui;
}
